﻿using System;
using System.Text;

namespace DitaImport
{
	/// <summary>
	/// This class simulates the TextBlock classes found in the Author-it core. It produces Author-it TopicText XML.
	/// </summary>
	/// <remarks></remarks>
	public class TextBlock
	{
		#region Fields (7) 

		/// <summary>
		/// Default table column width
		/// </summary>
		private const int _defaultColumnWidth = 2500;
		internal string Attributes = "";
		/// <summary>
		/// Backing field for the <see cref="BlockType"/> property
		/// </summary>
		public TextBlockType blockType;
		internal TextBlocks ChildTextBlocks;
		//TODO: Make default table column width a configuration setting
		internal int ColumnWidth = _defaultColumnWidth;
		/// <summary>
		/// Backing field for the <see cref="IsHeaderRow"/> property
		/// </summary>
		private bool isHeaderRow = false;
		/// <summary>
		/// Backing field for the <see cref="XmlText"/> property
		/// </summary>
		private string xmlText;

		#endregion Fields 

		#region Enums (1) 

		/// <summary>
		/// Contains values that specify the type of text in a <see cref="TextBlock"/>
		/// </summary>
		public enum TextBlockType : int
		{
			/// <summary>
			/// Unknown content type
			/// </summary>
			Unknown = 0,

			/// <summary>
			/// Paragraph content
			/// </summary>
			Paragraph = 1,

			/// <summary>
			/// Table content
			/// </summary>
			Table = 2,

			/// <summary>
			/// Table row content
			/// </summary>
			Row = 4,

			/// <summary>
			/// Table cell content
			/// </summary>
			Cell = 8
		}

		#endregion Enums 

		#region Constructors (1) 

		/// <summary>
		/// Initializes a new instance of the <see cref="TextBlock"/> class
		/// </summary>
		/// <param name="textBlockType"></param>
		public TextBlock(TextBlockType textBlockType)
		{
			this.ChildTextBlocks = new TextBlocks();  //Initialize the text blocks
			this.BlockType = textBlockType;  //Set the type for the text block
		}

		#endregion Constructors 

		#region Properties (3) 

/// <summary>
		/// Gets or sets the type of text block
		/// </summary>
		public TextBlockType BlockType
		{
			get { return this.blockType; }
			set { this.blockType = value; }
		}

		/// <summary>
		/// Gets or sets a value that specifies whether this <see cref="TextBlock"/> is a table header row
		/// </summary>
		/// <remarks>This property is only value if this <see cref="TextBlock"/> is of the type <see cref="TextBlockType.Row"/></remarks>
		public bool IsHeaderRow
		{
			get { return this.isHeaderRow; }
			set { this.isHeaderRow = value; }
		}

		/// <summary>
		/// Gets or sets the XML text for this <see cref="TextBlock"/>
		/// </summary>
		public string XmlText
		{
			get
			{
				return xmlText;  //Return the field value
			}
			set
			{
				//Public Const LineCharacter As String = Chr(15) 'SubSystems.TE.tc.LINE_CHAR
				//Public Const NBSpaceCharacter As String = Chr(14)  'SubSystems.TE.tc.NBSPACE_CHAR   'TODO: ???
				//Public Const NBDashCharacter As String = Chr(23) 'SubSystems.TE.tc.NBDASH_CHAR      'TODO: ???

				//HACK: to purge some of the white space
				value = value.Replace("\t", " ").Replace("   ", " ").Replace("  ", " ");
				xmlText = value.Trim(Convert.ToChar("\r"), Convert.ToChar("\n"), ' ', Convert.ToChar("\t")).Replace(Environment.NewLine, "<br/>");
			}
		}

		#endregion Properties 

		#region Methods (1) 

		// Public Methods (1) 

		/// <summary>
		/// Returns a string representation of this <see cref="TextBlock"/>
		/// </summary>
		/// <returns>String representation of this <see cref="TextBlock"/></returns>
		public override string ToString()
		{
			StringBuilder sb = new StringBuilder();  //Initialize the string builder that will store the string
			switch (this.BlockType)  //Determine the type for this text block
			{
				case TextBlockType.Paragraph:  //Paragraph content
					sb.Append(XmlText);  //Append the XML text
					foreach (var child in ChildTextBlocks)  //Iterate through each child text block
					{
						sb.Append(child.ToString());  //Append the string representation of the child text block
					}
					break;  //Exit the switch
				case TextBlockType.Table:  //Table content
					int rows = this.ChildTextBlocks.Count;  //Get the number of rows in the table
					int cols = this.ChildTextBlocks[0].ChildTextBlocks.Count;  //Get the number of columns in the table
					sb.AppendFormat("<table rows=\"{0}\" cols=\"{1}\" width=\"{2}\" >", rows, cols, cols * _defaultColumnWidth);  //Append the table tag
					foreach (var child in ChildTextBlocks)  //Iterate through each child text block
					{
						sb.Append(child.ToString());  //Append the string representation of the child text block
					}
					sb.Append("</table>");  //Close the table tag
					break;  //Exit the switch
				case TextBlockType.Row:  //Table row content
					if (IsHeaderRow)  //Is this a table header row?
					{
						sb.Append("<tr header=\"true\" rowheight=\"0\" >");  //Append the table row tag with the header attribute set to true
					}
					else
					{
						sb.Append("<tr rowheight=\"0\" >");  //Append the table row tag
					}
					if (ChildTextBlocks.Count > 0 && ChildTextBlocks.Count < 4) // for tables with fewer than 4 columns, make the last column wider
					{
						int lastColumn = ChildTextBlocks.Count - 1;  //Set the index for the last column
						ChildTextBlocks[lastColumn].ColumnWidth = (4 - lastColumn) * _defaultColumnWidth;  //Set the width of the last column
					}
					foreach (var child in ChildTextBlocks)  //Iterate through each child text block
					{
						if (IsHeaderRow)  //Is this a header row?
						{
							child.Attributes = "borders=\"15\" bordercolors=\"12632256\" bgcolor=\"14211288\" "; // dark gray bgcolor + borders
						}
						else
						{
							child.Attributes = "borders=\"15\" bordercolors=\"12632256\" bgcolor=\"15921906\" ";  // light gray bgcolor + borders
						}
						sb.Append(child.ToString());  //Append the string representation of the child text block
					}
					sb.Append("</tr>");  //Close the table row tag
					break;  //Exit the switch
				case TextBlockType.Cell:  //Table cell content
					sb.AppendFormat("<td width=\"{0}\" {1}>", ColumnWidth, Attributes);  //Append the table data tag opening
					foreach (var child in ChildTextBlocks)  //Iterate through each child text block
					{
						sb.Append(child.ToString());  //Append the string representation of the child text block
					}
					sb.Append("</td>");  //Close the table data tag
					break;  //Exit the switch
				default:  //Unhandled type
					throw new ArgumentException("Unknown TextBlock type", "TextBlock.BlockType");  //Throw an exception
			}
			return sb.ToString();
		}

		#endregion Methods 
	}
}